
// Copyright (C) 2007 Richard Uhler
// This file is part of Esiply.
//
// Esiply is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License, Version 2,
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include <assert.h>
//#include <gc_allocator.h>
#include <stdio.h>
#include "Completion.h"
#include "FormalParameterList.h"
#include "FunctionDeclaration.h"
#include "Object.h"
#include "RegularFunction.h"
#include "Scope.h"
#include "SourceElement.h"
#include "SourceElements.h"
#include "String.h"
#include "Undefined.h"
#include "Value.h"

SourceElements::SourceElements(SourceElement* element)
    : m_line_number(-1)
{
    push_back(element);
}

void SourceElements::push_back(SourceElement* element)
{
    m_elements.push_back(element);
    if (element->isStmt())
    {
        m_stmts.push_back(element->getStmt());
    }
    else
    {
        m_fdecs.push_back(element->getFDec());
    }
}

Value* SourceElements::run(Scope* scope)
{

    // Ecma 14 TODO: this is very unclear in the standard.
    // 1. Process function declarations
    for (unsigned int i = 0; i < m_fdecs.size(); i++)
    {
        Function* func = new RegularFunction(scope,
                m_fdecs[i]->get_params()->as_string()->c_str(),
                m_fdecs[i]->get_body());
        // TODO: Attributes determined by the type of code
        // TODO: function should set its own prototype
        func->set_prototype(Function::prototype);
        scope->get_variable()->put(m_fdecs[i]->get_identifier(), func, PA_EMPTY);
		//add Synchronized support
		if(m_fdecs[i]->get_sync() == 1){
			func->set_sync(1);
		}else{
			func->set_sync(0);
		}
    }

    // Ecma 10.1.3
    // For each VariableDeclaration in the code, create a property of the
    // variable object whose name is identifier, and value is undefined.
    // But don't overwrite anything existing
    std::vector<String*> ids;
    for (unsigned int i = 0; i < m_stmts.size(); i++)
    {
        m_stmts[i]->getDeclaredVariables(ids);
    }
    for (unsigned int i = 0; i < ids.size(); i++)
    {
        if (!scope->get_variable()->has(ids[i]))
        {
            scope->get_variable()->put(ids[i], Undefined::undefined,
                    PA_DONT_DELETE);
        }
    }

    // 2. Evaluate SourceElements
    // 3. Return the result
    Value* res = Undefined::undefined;
    for (unsigned int i = 0; i < m_stmts.size(); i++)
    {
        //  1. Evaluate Source Elements
        res = m_stmts[i]->execute(scope);

        // Check for exceptions. TODO: this should be made nice and fixed
        // in some way. In other words: it's just temporary for developement.
        if (res->isException())
        {
            m_file = m_file ? m_file : new String("???");
            fprintf(stderr, "%s: %i: Exception thrown\n",
                    m_file->c_str(), m_line_number);
        }

        // 2. if res is an abrupt compeltion, return it
        if (res->completion()->type() != CT_NORMAL)
        {
            return res;
        }
    }
    return res;
}

void SourceElements::setLineNumber(int line)
{
    m_line_number = line;
}

void SourceElements::setFile(String* file)
{
    m_file = file;
}

